// request 网络请求工具 更详细的 api 文档: https://github.com/umijs/umi-request
import React from 'react';
import { getDvaApp } from 'umi';
import { Divider, Modal, notification, Typography } from 'antd';
import type { ModalFuncProps } from 'antd/lib/modal';
import { extend } from 'umi-request';
import type { ResponseError } from 'umi-request';
import { getModelData, generateUuid } from '@/utils/utils';
import cache from '@/utils/cache';
import URLMAP from './urlMap';
import { dynamicHeader } from './utils';
import RequestTokenBucket from './tokenbucket';
import { getMaskHeaderKey, getSecretKey, decryptByAES } from './secret';
import type { Request, ErrorProp } from './request-ts';

const { serviceIdMap, urlMap } = URLMAP;
const { Paragraph } = Typography;
const errorMessage = {
  Timeout: '请求超时',
  TypeError: '网络异常',
};

// 异常处理程序
export const TraceIdKey = 'x-g-trace-id';
export const StateKey = 'x-g-process-result';
export const errorDruation = null; //错误信息不消失
export const successDruation = 5;
export const warnDruation = 5;

// 默认开始请求前置令牌桶
RequestTokenBucket.start();

notification.config({
  placement: 'bottomRight',
  bottom: 0,
  duration: 2,
  getContainer: () => document.querySelector('.gant-layout' || document.body),
});

const defaultModalErrorInfo: ModalFuncProps = {
  title: '系统错误',
  maskClosable: true,
  okText: '知道了',
  okButtonProps: { size: 'small' },
  zIndex: 2000,
  centered: true,
  getContainer: () => document.querySelector('.gant-layout' || document.body),
  onOk: (cb) => cb(),
};

// 异常程序时展示的内容
export const ErrorContent = ({ traceId, type = 'normal', msg = '', msgNode }: ErrorProp) => {
  if (type == 'normal') {
    return (
      <div style={{ wordBreak: 'break-all' }}>
        <div
          style={{
            maxHeight: 'calc(100vh - 180px)',
            overflowY: 'auto',
          }}
        >
          {msgNode || <span dangerouslySetInnerHTML={{ __html: msg }} />}
        </div>
        <div style={{ marginTop: 30 }}>
          <Divider orientation="left" />
          {'错误跟踪号'}:<Paragraph copyable>{traceId}</Paragraph>
        </div>
      </div>
    );
  } else {
    const errorMsg =
      type == 'system' ? <span dangerouslySetInnerHTML={{ __html: msg }} /> : <span>{msg || '未知异常'}</span>;
    return (
      <div style={{ marginTop: '10px' }}>
        <div>
          {'请将错误跟踪号'}
          {'提交给系统管理员以便进一步分析'}
        </div>
        <div>
          <Paragraph copyable>{traceId}</Paragraph>
        </div>
        <div>
          {'错误信息：'}
          {errorMsg}
        </div>
      </div>
    );
  }
};

// 错误处理
const errorHandler = (error: ResponseError) => {
  const { response, type } = error;
  const TraceId = response && response.headers.get(TraceIdKey);
  const msg = !TraceId ? errorMessage[type] : '';
  Modal.error({
    ...defaultModalErrorInfo,
    content: <ErrorContent traceId={TraceId} msg={msg} type="abnormal" />,
  });
  return Promise.reject(error);
};

// 请求统一配置
const extendRequest = extend({
  errorHandler,
  getResponse: true,
  timeout: 30 * 60 * 1000, // 配置request请求时的默认参数
  suffix: '.api', // 统一使用api后缀
});

// 进入调试模式
const gantdDubug = () => {
  if (cache.debuggingCache.get('debuggingCache')) {
    return { 'X-G-DEBUG': cache.debuggingCache.get('debuggingCache') };
  } else {
    return {};
  }
};

// 请求拦截, 验证登录状态
extendRequest.interceptors.request.use(function requestInterceptor(url, options) {
  const newOption: any = { ...options };
  const isAddPss = url.endsWith('/productStructure/find.api');
  const pssTypeCode = options?.data?.filterInfo?.pssTypeCode;
  newOption.headers = {
    needHtmlEscape: 'false',
    ...gantdDubug(),
    ...options.headers,
    ...dynamicHeader.current,
    ...(isAddPss && !!pssTypeCode ? { pssTypeCode: pssTypeCode } : {}),
  };
  if (!cache.debuggingCache.get('debuggingCache')) {
    delete newOption['X-G-DEBUG'];
  }
  return {
    url,
    options: newOption,
  };
});

const request = (url, options, extra: Config) => {
  const {
    showSuccess = false,
    successMessage,
    showWraning = true,
    showError = true,
    getParams = false,
    isStream = false,
    duration = successDruation,
  } = Object(extra);
  RequestTokenBucket.use();
  const X_G_TRACE_ID = generateUuid();
  //传入拼接的url
  let newUrl = url;
  if (options?.serviceId) {
    newUrl = `/${urlMap[options.serviceId]}${url}`;
    delete options.serviceId;
  } else {
    const [_, urlPrefix] = url.split('/');
    newUrl = serviceIdMap[urlPrefix] ? `/${serviceIdMap[urlPrefix]}${url}` : url;
  }
  _.set(options, 'headers.X-G-TRACE-ID', X_G_TRACE_ID);
  return extendRequest(newUrl, options).then((params) => {
    const { data: serveData, response } = params;
    const { state, message: msg, warnDescription, log, traces } = serveData;
    const TraceId = response.headers.get(TraceIdKey) || X_G_TRACE_ID;
    if (((log && log.length != 0) || (traces && traces.length != 0)) && cache.debuggingCache.get('debuggingCache')) {
      const { dispatch } = getDvaApp()._store;
      const debuggingData = getModelData('global.debuggingData');
      const obj = {
        log,
        api: newUrl,
        traces,
        id: generateUuid(),
      };
      debuggingData.unshift(obj);
      dispatch({
        type: 'global/save',
        payload: {
          debuggingData,
        },
      });
    }
    const DataMaskValue = response.headers.get(getMaskHeaderKey()) || '';
    if (DataMaskValue != '') {
      const secretKey = getSecretKey(DataMaskValue);
      const base64Key = Buffer.from(secretKey, 'utf8'.toString('base64'));
      const decryption = decryptByAES(serveData.data, base64Key, base64Key);
      serveData.data = JSON.parse(decryption);
    }

    if (state === 'success') {
      // 后台返回成功
      if (showSuccess) {
        notification.success({
          message: successMessage || msg || '操作成功',
          duration,
        });
      }
    }
    // // 警告
    if (state === 'warn' && showWraning) {
      notification.info({
        duration: warnDruation,
        message: warnDescription || msg,
        description: (
          <>
            {'错误跟踪号'}:<Paragraph copyable>{TraceId}</Paragraph>
          </>
        ),
      });
    }
    if (state === 'error' && showError) {
      notification.warning({
        duration: errorDruation,
        message: '提示',
        description: <ErrorContent msg={serveData.message} traceId={TraceId} />,
      });
      return Promise.reject(msg);
    }
    if (state === 'sys-error') {
      Modal.error({
        ...defaultModalErrorInfo,
        content: <ErrorContent msg={msg} traceId={TraceId} type="system" />,
      });
      return Promise.reject(msg);
    }
    return getParams ? params : isStream ? response : serveData.data;
  });
};

// 手动定义各HTTP方法
request.get = function (url, options = {}, ...behaver) {
  return request(url, { ...options, method: 'get' }, ...behaver);
};

request.post = function (url, options = {}, ...behaver) {
  return request(url, { ...options, method: 'post' }, ...behaver);
};

request.put = function (url, options = {}, ...behaver) {
  return request(url, { ...options, method: 'put' }, ...behaver);
};

request.delete = function (url, options = {}, ...behaver) {
  return request(url, { ...options, method: 'delete' }, ...behaver);
};

export default request as Request;
